package com.cskaoyan.javase.oop3._5lambda._4example;

/**
 * Lambda表达式的本质是将一个方法作为一个对象
 * 实际应用场景下,这个对象依赖于这个方法可以用来表示一种灵活的规则
 * 比较典型的,用途比较多的有:
 * 	    a.过滤(filter)
 * 	    b.映射(map)
 * 	    c.排序(sort)
 * 	    等等
 *
 * 以下我们手写一个过滤器规则的实现,用来灵活的过滤所有的Object对象数组(实际上可以过滤所有的数组)
 *
 * @since 10:04
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 1.过滤一个int数组
        Integer[] arr1 = {1, 2, 3, 4, 5};
        // 表示没有过滤规则,任何元素都接收
        Object[] result1 = filterObjectArrByIFilter(arr1, o -> true);
        for (Object ele : result1) {
            System.out.println(((Integer) ele));
        }
        System.out.println("-------------------");
        // 过滤大于3的元素
        Object[] result2 = filterObjectArrByIFilter(arr1, o -> ((Integer) o) <= 3);
        for (Object ele : result2) {
            System.out.println(((Integer) ele));
        }
        System.out.println("-------------------");
        // 2.过滤String数组
        String[] arr2 = {"123", "a666", "ahello", "111"};
        // 表示过滤掉长度为3的String字符串
        Object[] result3 = filterObjectArrByIFilter(arr2, o -> ((String) o).length() != 3);
        for (Object ele : result3) {
            System.out.println(((String) ele));
        }
        System.out.println("-----------------");
        // 3.过滤Student对象数组
        Student[] arr3 = new Student[5];
        arr3[0] = new Student(18, 750);
        arr3[1] = new Student(28, 470);
        arr3[2] = new Student(38, 550);
        arr3[3] = new Student(8, 380);
        arr3[4] = new Student(16, 720);
        // 过滤规则: 未成人禁止入内
        Object[] result4 = filterObjectArrByIFilter(arr3, o -> ((Student)
                o).getAge() >= 18);
        for (Object ele : result4) {
            Student s = (Student) ele;
            s.printStu();
        }
        System.out.println("--------------");

        /*
            复杂的过滤规则:
                1.先过滤掉age大于等于18岁的人
                2.过滤掉考700分以上的学霸
         */
        Object[] result5 = filterObjectArrByIFilter(arr3, Demo::myAccept);
        for (Object ele : result5) {
            ((Student) ele).printStu();
        }
    }

    public static boolean myAccept(Object o) {
        Student s = (Student) o;
        if (s.getAge() >= 18) {
            return false;
        }
        // 运行到这里age肯定小于18
        if (s.getScore() > 700) {
            return false;
        }
        return true;
    }

    /*
        功能接口当中的抽象方法仅表示过滤的规则
        具体完成过滤,还需要一个过滤的实现方法
        这个方法:
            1.需要传入一个被过滤的数组,返回一个过滤完成的新数组
            2.既然IFilter接口表示过滤规则,所以过滤的规则也要传入方法
        过滤实际上是删除数组中的元素,是真的删除,需要:
            1.新建一个数组,这个数组的长度是根据过滤规则,没有被过滤掉元素的个数
            2.给新建的数组赋值,把没有被过滤掉的元素,挨个赋值进去就完了

        在这个方法中,这个过滤的规则,如何生效?
            accept方法,需要传入一个Object对象,然后返回布尔值,true表示留下的元素,false表示过滤掉的元素
            所以只需要每个Object对象数组中的元素,都传入给accept方法,就可以判断哪些元素需要留下了!

     */
    public static Object[] filterObjectArrByIFilter(Object[] target, IFilter filter) {
        int count = 0;
        for (Object ele : target) {
            if (filter.accept(ele)) {
                // 留下的元素
                count++;
            }
        }
        Object[] result = new Object[count];
        // 给新数组赋值
        int newIndex = 0;
        for (Object ele : target) {
            if (filter.accept(ele)) {
                // 留下的元素
                result[newIndex] = ele;
                newIndex++;
            }
        }
        return result;
    }
}

/*
    首先需要一个表示过滤规则的功能接口
    既然是过滤,这个抽象方法:
        返回值类型写布尔类型,true表示被接受的数据,false表示被过滤掉的数据
        由于是用来表示对Object对象数组的过滤,所以这个方法需要传入Object对象
 */
@FunctionalInterface
interface IFilter {
    boolean accept(Object o);
}

class Student {
    private int age;
    private double score;

    public Student() {
    }

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    public int getAge() {
        return age;
    }

    public double getScore() {
        return score;
    }

    public void printStu() {
        System.out.println("age = " + age + ",score = " + score);
    }
}